package com.zx.flow.core.execute.eventhandler;

import com.zx.flow.api.config.FlowConfig;
import com.zx.flow.api.config.FlowConfigNode;
import com.zx.flow.api.dict.FlowDict.Event;
import com.zx.flow.api.dict.FlowDict.Status;
import com.zx.flow.api.exception.FlowException;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.model.FlowNode;
import com.zx.flow.api.execute.request.FlowParamCancel;
import com.zx.flow.api.execute.request.FlowParamEnd;
import com.zx.flow.api.execute.request.FlowParamNodeFinish;
import com.zx.flow.api.execute.response.FlowResult;
import com.zx.flow.api.util.AssertUtil;
import com.zx.flow.api.util.FlowDataUtil;
import com.zx.flow.core.execute.EventHandler;
import java.util.Objects;

/**
 * 事件处理器【流程->取消】
 */
public class EventFlowCancelHandler extends EventHandler<FlowParamCancel> {

    @Override
    public boolean in(FlowContext flow, FlowParamCancel param) {
        AssertUtil.checkApplyAccount(flow, param.getAccountCode());
        return flow != null && !Objects.equals(flow.getStatus(), Status.flowEnd);
    }

    @Override
    public FlowResult on(FlowContext flow, FlowParamCancel param) {
        if (!Objects.equals(param.getAccountCode(), flow.getApplyAccountCode())) {
            throw new FlowException("只有申请人允许取消流程");
        }

        FlowConfig config = this.getFlowConfig(flow.getFlowConfigCode(), flow.getFlowConfigId());
        FlowConfigNode endNodeConfig = config.getEndNode();

        if (Objects.equals(flow.getStatus(), Status.flowDoing)) {
            // 获得最新的节点
            FlowNode currentNode = FlowDataUtil.getCurrent(flow);
            // 完成本节点
            flow = this.execute(new FlowParamNodeFinish(currentNode.getFlowId(), currentNode.getId(),
                            endNodeConfig.getCode(), Event.flowCancel, param.getCancelReason(), param.getAccountCode()))
                    .getFlowContext();
            // 触发监听
            this.listener(currentNode, Event.flowCancel);
        }
        // 流向end
        flow = this.execute(new FlowParamEnd(param.getId())).getFlowContext();

        return FlowResult.ok(flow);
    }
}
